﻿using RoadQualityEvalAPI.Helpers;
using RoadQualityEvalAPI.Models;
using RoadQualityEvaluatorData.Domain.Entities;
using RoadQualityEvaluatorData.DomainServices.Generic;
using RoadQualityEvaluatorData.DomainServices.Repositories;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Mvc;


namespace RoadQualityEvalAPI.Controllers
{

    [Authorize(Roles = "Admin")]
    public class AdminController : Controller
    {

        private TripStatsRepository _tripStatsRepo;
        private UserRepository _usersRepo;
        private RoleRepository _rolesRepo;
        private MapSectionRepository _mapSectionsRepo;
        private PotholeRepository _potholeRepo;
        private SpeedbumpRepository _speedbumpRepo;


        public ActionResult Index()
        {
            this._tripStatsRepo = new TripStatsRepository();

            var trips = new List<TripStatsModel>();

            if (_tripStatsRepo.GetAll().Count > 0)
            {
                foreach (var trip in _tripStatsRepo.GetAll())
                {
                    trips.Add(new TripStatsModel()
                    {
                        CreatedAt = trip.CreatedAt,
                        Info = trip.TripInfo,
                        TripAverageRoughness = trip.TripAverageRoughness,
                        TripAverageSpeed = trip.TripAverageSpeed,
                        TripDistance = trip.TripDistance,
                        TripNoOfSpeedbumps = trip.TripNoOfSpeedbumps,
                        TripNoOfPotholes = trip.TripNoOfPotholes,
                        TripDurationMillis = trip.TripDurationMillis
                    });
                }
            }

            return View("~/Views/Admin/Admin.cshtml", trips);
        }

        public ActionResult Home()
        {
            this._tripStatsRepo = new TripStatsRepository();

            var trips = new List<TripStatsModel>();

            if (_tripStatsRepo.GetAll().Count > 0)
            {
                foreach (var trip in _tripStatsRepo.GetAll())
                {
                    trips.Add(new TripStatsModel()
                    {
                        CreatedAt = trip.CreatedAt,
                        Info = trip.TripInfo,
                        TripAverageRoughness = trip.TripAverageRoughness,
                        TripAverageSpeed = trip.TripAverageSpeed,
                        TripDistance = trip.TripDistance,
                        TripNoOfSpeedbumps = trip.TripNoOfSpeedbumps,
                        TripNoOfPotholes = trip.TripNoOfPotholes,
                        TripDurationMillis = trip.TripDurationMillis
                    });
                }
            }

            return View("~/Views/Admin/_GeneralStats.cshtml", trips);
        }


        public ActionResult RemoveFalseTripStats()
        {
            this._tripStatsRepo = new TripStatsRepository();

            foreach (var ts in _tripStatsRepo.GetAll().Where(t => t.TripDistance <= 0.1 && t.TripAverageSpeed == 0 && t.TripAverageRoughness == 0).ToList())
            {
                _tripStatsRepo.DeleteById(ts.Id);
            }

            return Index();
        }

        public ActionResult Users()
        {
            this._usersRepo = new UserRepository();

            List<UserModel> users = new List<UserModel>();

            foreach (var x in _usersRepo.GetAll())
            {
                users.Add(new UserModel()
                {
                    UserId = x.Id,
                    CreatedAt = x.CreatedAt,
                    Email = x.Email,
                    UserInfo = x.Info,
                    UserName = x.Username
                });
            }

            return PartialView("~/Views/Admin/_UsersAdministration.cshtml", users);
        }

        public ActionResult Roles()
        {
            _rolesRepo = new RoleRepository();

            List<RoleModel> roles = new List<RoleModel>();

            foreach (var r in _rolesRepo.GetAll())
            {
                RoleModel role = new RoleModel()
                {
                    RoleId = r.Id,
                    RoleInfo = r.RoleDescription,
                    RoleName = r.RoleName
                };

                roles.Add(role);
            }

            return PartialView("~/Views/Admin/_RolesAdministration.cshtml", roles);
        }

        public ActionResult MapSections()
        {
            _mapSectionsRepo = new MapSectionRepository();

            List<MapSectionModel> list = new List<MapSectionModel>();
            IList<PotholeModel> mapSectionPotholes;
            IList<SpeedbumpModel> mapSectionSpeedbumps;

            foreach (var x in _mapSectionsRepo.GetAll())
            {
                mapSectionPotholes = new List<PotholeModel>();
                mapSectionSpeedbumps = new List<SpeedbumpModel>();


                foreach (var p in x.Potholes)
                {
                    mapSectionPotholes.Add(new PotholeModel()
                    {
                        CreatedAt = p.CreatedAt,
                        Description = p.Description,
                        Location = new LocationModel() { Latitude = p.Location.Latitude, Longitude = p.Location.Longitude },
                        Quality = p.Quality,
                        Type = p.Type,
                        Username = p.UserWhoCollected.Username
                    });
                }

                foreach (var sb in x.Speedbumps)
                {
                    mapSectionSpeedbumps.Add(new SpeedbumpModel()
                    {
                        CreatedAt = sb.CreatedAt,
                        Description = sb.Description,
                        Location = new LocationModel() { Latitude = sb.Location.Latitude, Longitude = sb.Location.Longitude },
                        Username = sb.UserWhoCollected.Username
                    });
                }


                MapSectionModel model = new MapSectionModel()
                {
                    MapSectionId = x.Id,
                    Name = x.Name,
                    StreetName = x.StreetName,
                    StartLocation = new LocationModel { Latitude = x.StartLocation.Latitude, Longitude = x.StartLocation.Longitude },
                    EndLocation = new LocationModel { Latitude = x.EndLocation.Latitude, Longitude = x.EndLocation.Longitude },
                    Description = x.Description,
                    OverallQuality = x.OverallQuality,
                    RoughnessQuality = x.RugosityQuality,
                    Potholes = mapSectionPotholes,
                    Speedbumps = mapSectionSpeedbumps
                };

                list.Add(model);
            }

            return PartialView("~/Views/Admin/_MapSectionsAdministration.cshtml", list);
        }

        public ActionResult Potholes()
        {
            _potholeRepo = new PotholeRepository();

            List<PotholeModel> modelList = new List<PotholeModel>();

            foreach (var pot in _potholeRepo.GetAll())
            {
                modelList.Add(new PotholeModel
                {
                    CreatedAt = pot.CreatedAt,
                    Description = pot.Description,
                    Location = new LocationModel() { Latitude = pot.Location.Latitude, Longitude = pot.Location.Longitude },
                    Quality = pot.Quality,
                    Type = pot.Type,
                    Username = pot.UserWhoCollected.Email
                });
            }

            return PartialView("~/Views/Admin/_PotholesAdministration.cshtml", modelList);
        }


        public ActionResult RemoveFalsePotholes(string selectedPotholes)
        {
            int dateOffsetInDays = 0;

            if (selectedPotholes.Equals("TwoWeeks"))
            {
                dateOffsetInDays = 14;
            }
            if (selectedPotholes.Equals("OneWeek"))
            {
                dateOffsetInDays = 7;
            }
            if (selectedPotholes.Equals("ThreeDays"))
            {
                dateOffsetInDays = 3;
            }

            _potholeRepo = new PotholeRepository();

            foreach (var pothole in _potholeRepo.GetAll().Where(p => (GeneralHelpers.ConvertFromJavaDateStringToDateTime(p.CreatedAt).CompareTo(DateTime.Now.AddDays(-(dateOffsetInDays))) < 0) && p.Quality < 3).ToList())
            {
                _potholeRepo.DeleteById(pothole.Id);
            }

            return Index();
        }

        public ActionResult Speedbumps()
        {
            _speedbumpRepo = new SpeedbumpRepository();

            List<SpeedbumpModel> modelList = new List<SpeedbumpModel>();

            foreach (var sb in _speedbumpRepo.GetAll())
            {
                modelList.Add(new SpeedbumpModel
                {
                    CreatedAt = sb.CreatedAt,
                    Description = sb.Description,
                    Location = new LocationModel() { Latitude = sb.Location.Latitude, Longitude = sb.Location.Longitude },
                    Username = sb.UserWhoCollected.Email
                });
            }

            return PartialView("~/Views/Admin/_SpeedbumpsAdministration.cshtml", modelList);
        }

        public ActionResult CreateUser()
        {
            _rolesRepo = new RoleRepository();

            UserModel model = new UserModel();
            model.UserRoles = new List<RoleModel>();

            foreach (var r in _rolesRepo.GetAll())
            {
                RoleModel role = new RoleModel()
                {
                    RoleId = r.Id,
                    RoleInfo = r.RoleDescription,
                    RoleName = r.RoleName,
                    Selected = false
                };

                model.UserRoles.Add(role);
            }

            return PartialView("~/Views/Admin/_CreateUser.cshtml", model);
        }

        [HttpPost]
        public ActionResult CreateUser(UserModel model)
        {
            UnitOfWork uo = new UnitOfWork();
            _usersRepo = new UserRepository(uo);
            _rolesRepo = new RoleRepository(uo);
            // TODO: Really hash the pass before commiting
            string hash = model.HashedPass;

            if (ModelState.IsValid)
            {
                var selectedRoles = model.UserRoles.Where(r => r.Selected == true).ToList();

                List<Role> roles = new List<Role>();
                foreach (var selectedRole in selectedRoles)
                {
                    roles.Add(_rolesRepo.GetRoleByName(selectedRole.RoleName));
                }

                var user = new User()
                {
                    CreatedAt = DateTime.Now,
                    Email = model.Email,
                    Info = model.UserInfo,
                    Username = model.UserName,
                    HashedPassword = hash,
                    UserRoles = roles
                };

                _usersRepo.Add(user);

                return Index();
            }

            ModelState.AddModelError("", "Something went wrong with creating a new user");
            return PartialView("~/Views/Admin/_CreateUser.cshtml", model);
        }


        public ActionResult CreateRole()
        {
            RoleModel model = new RoleModel();
            return PartialView("~/Views/Admin/_CreateRole.cshtml", model);
        }

        [HttpPost]
        public ActionResult CreateRole(RoleModel model)
        {
            _rolesRepo = new RoleRepository();

            if (ModelState.IsValid)
            {
                var role = new Role()
                {
                    RoleName = model.RoleName,
                    RoleDescription = model.RoleInfo
                };

                _rolesRepo.Add(role);

                return Index();
            }

            ModelState.AddModelError("", "Something went wrong with creating a new role");
            return PartialView("~/Views/Admin/_CreateRole.cshtml", model);
        }

        public ActionResult CreateMapSection()
        {
            MapSectionModel model = new MapSectionModel();
            return PartialView("~/Views/Admin/_CreateMapSection.cshtml", model);
        }

        [HttpPost]
        public ActionResult CreateMapSection(MapSectionModel model)
        {
            _mapSectionsRepo = new MapSectionRepository();

            if (ModelState.IsValid)
            {
                var mapSection = new MapSection()
                {
                    Name = model.Name,
                    Description = model.Description,
                    StreetName = model.StreetName,
                    StartLocation = new Location() { Latitude = model.StartLocation.Latitude, Longitude = model.StartLocation.Longitude },
                    EndLocation = new Location() { Latitude = model.EndLocation.Latitude, Longitude = model.EndLocation.Longitude }
                };

                _mapSectionsRepo.Add(mapSection);
                return Index();
            }

            ModelState.AddModelError("", "Something went wrong with creating a new map section");
            return PartialView("~/Views/Admin/_CreateMapSection.cshtml", model);


        }


        public ActionResult EditUser(int id)
        {
            UnitOfWork uo = new UnitOfWork();
            _usersRepo = new UserRepository(uo);
            _rolesRepo = new RoleRepository(uo);


            var user = _usersRepo.GetById(id);

            UserModel model = new UserModel()
            {
                UserId = user.Id,
                CreatedAt = user.CreatedAt,
                Email = user.Email,
                UserName = user.Username,
                UserInfo = user.Info,
                HashedPass = user.HashedPassword
            };

            model.UserRoles = new List<RoleModel>();

            foreach (var r in user.UserRoles)
            {
                RoleModel role = new RoleModel()
                {
                    RoleId = r.Id,
                    RoleInfo = r.RoleDescription,
                    RoleName = r.RoleName,
                    Selected = true
                };

                model.UserRoles.Add(role);
            }

            foreach (var r in _rolesRepo.GetAll())
            {
                if (model.UserRoles.Where(mr => mr.RoleName.Equals(r.RoleName)).FirstOrDefault() == null)
                {
                    RoleModel role = new RoleModel()
                    {
                        RoleId = r.Id,
                        RoleInfo = r.RoleDescription,
                        RoleName = r.RoleName,
                        Selected = false
                    };

                    model.UserRoles.Add(role);
                }
            }

            return PartialView("~/Views/Admin/_EditUser.cshtml", model);
        }

        [HttpPost]
        public ActionResult EditUser(int id, UserModel model)
        {
            UnitOfWork uo = new UnitOfWork();
            _usersRepo = new UserRepository(uo);
            _rolesRepo = new RoleRepository(uo);

            // TODO: Really hash the pass before commiting
            string hash = model.HashedPass;

            if (ModelState.IsValid)
            {
                var selectedRoles = model.UserRoles.Where(r => r.Selected == true).ToList();

                List<Role> roles = new List<Role>();
                foreach (var selectedRole in selectedRoles)
                {
                    roles.Add(_rolesRepo.GetRoleByName(selectedRole.RoleName));
                }

                var user = _usersRepo.GetById(id);

                user.CreatedAt = DateTime.Now;
                user.Email = model.Email;
                user.Info = model.UserInfo;
                user.Username = model.UserName;
                user.HashedPassword = hash;
                user.UserRoles = roles;


                _usersRepo.Update(user);

                return Index();
            }

            ModelState.AddModelError("", "Something went wrong with editing the user");
            return PartialView("~/Views/Admin/_EditUser.cshtml", model);
        }

        public ActionResult EditRole(string rolename)
        {
            _rolesRepo = new RoleRepository();

            var role = _rolesRepo.GetRoleByName(rolename);

            RoleModel model = new RoleModel()
            {
                RoleId = role.Id,
                RoleName = role.RoleName,
                RoleInfo = role.RoleDescription
            };

            return PartialView("~/Views/Admin/_EditRole.cshtml", model);
        }

        [HttpPost]
        public ActionResult EditRole(int id, RoleModel model)
        {
            _rolesRepo = new RoleRepository();

            if (ModelState.IsValid)
            {
                var role = _rolesRepo.GetById(id);

                role.RoleName = model.RoleName;
                role.RoleDescription = model.RoleInfo;

                _rolesRepo.Update(role);

                return Index();
            }

            ModelState.AddModelError("", "Something went wrong with editing the role");
            return PartialView("~/Views/Admin/_EditRole.cshtml", model);
        }

        public ActionResult EditMapSection(string name)
        {
            _mapSectionsRepo = new MapSectionRepository();

            var mapsection = _mapSectionsRepo.GetMapSectionByName(name);

            MapSectionModel model = new MapSectionModel()
            {
                MapSectionId = mapsection.Id,
                Name = mapsection.Name,
                Description = mapsection.Description,
                StreetName = mapsection.StreetName,
                StartLocation = new LocationModel() { Latitude = mapsection.StartLocation.Latitude, Longitude = mapsection.StartLocation.Longitude },
                EndLocation = new LocationModel() { Latitude = mapsection.EndLocation.Latitude, Longitude = mapsection.EndLocation.Longitude },
            };

            return PartialView("~/Views/Admin/_EditMapSection.cshtml", model);
        }


        [HttpPost]
        public ActionResult EditMapSection(int id, MapSectionModel model)
        {
            _mapSectionsRepo = new MapSectionRepository();

            if (ModelState.IsValid)
            {
                var mapSection = _mapSectionsRepo.GetById(id);

                mapSection.Name = model.Name;
                mapSection.Description = model.Description;
                mapSection.StreetName = model.StreetName;
                mapSection.StartLocation = new Location() { Latitude = model.StartLocation.Latitude, Longitude = model.StartLocation.Longitude };
                mapSection.EndLocation = new Location() { Latitude = model.EndLocation.Latitude, Longitude = model.EndLocation.Longitude };

                _mapSectionsRepo.Update(mapSection);

                return Index();
            }

            ModelState.AddModelError("", "Something went wrong with editing the map section");
            return PartialView("~/Views/Admin/_EditMapSection.cshtml", model);
        }


        public ActionResult ReassignPotholesSpeedbumpsToMapSections()
        {
            UnitOfWork uo = new UnitOfWork();
            PotholeHelper potholeHelper = new PotholeHelper(uo);
            SpeedbumpHelper sbHelper = new SpeedbumpHelper(uo);

            foreach (var pot in potholeHelper.PotholeRepo.GetAll())
            {
                potholeHelper.AssignPotholeToMapSection(pot);
            }

            foreach (var sb in sbHelper.SpeedbumpRepo.GetAll())
            {
                sbHelper.AssignSpeedbumpToMapSection(sb);
            }

            return Index();
        }

        
        public ActionResult DeleteUser(int id)
        {
            _usersRepo = new UserRepository();

            _usersRepo.DeleteById(id);

            return Index();
        }

        
        public ActionResult DeleteRole(int id)
        {
            _rolesRepo = new RoleRepository();

            _rolesRepo.DeleteById(id);

            return Index();
        }

        
        public ActionResult DeleteMapSection(int id)
        {
            _mapSectionsRepo = new MapSectionRepository();

            _mapSectionsRepo.DeleteById(id);

            return Index();
        }

    }
}
